home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / lfs / lfsFileIndex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  27.7 KB  |  883 lines

  1. /* 
  2.  * lfsFileIndex.c --
  3.  *
  4.  *    Routines to allow moving through a files block pointers.  The method
  5.  *    of using these routines is the following:
  6.  *
  7.  *        1) Call LfsFile_GetIndex to get the index of a specified block
  8.  *                of a specified file.
  9.  *        2) Call LfsFile_SetIndex to set the index of a specified block
  10.  *                of a specified file.
  11.  *        2) Call LfsFile_TruncIndex to truncate the index of a specified
  12.  *                file to the specified block number.
  13.  *
  14.  *
  15.  *    The data structure operated on is the disk map kept in the disk
  16.  *    file descriptor (LfsFileDescriptor).  This has 10 direct block pointers,
  17.  *    then a singly indirect block full of direct block pointers,
  18.  *    then a doubly indirect block full of singly indirect pointers.
  19.  *    The triple indirect block pointer is not implemented, limiting
  20.  *    the file size to 40K + 4Meg + 4Gigabytes.
  21.  *
  22.  * Copyright 1987 Regents of the University of California
  23.  * All rights reserved.
  24.  * Permission to use, copy, modify, and distribute this
  25.  * software and its documentation for any purpose and without
  26.  * fee is hereby granted, provided that the above copyright
  27.  * notice appear in all copies.  The University of California
  28.  * makes no representations about the suitability of this
  29.  * software for any purpose.  It is provided "as is" without
  30.  * express or implied warranty.
  31.  */
  32.  
  33. #ifndef lint
  34. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/lfs/lfsFileIndex.c,v 1.11 92/06/01 15:04:53 kupfer Exp $ SPRITE (Berkeley)";
  35. #endif not lint
  36.  
  37. #include <sprite.h>
  38. #include <fs.h>
  39. #include <lfs.h>
  40. #include <lfsInt.h>
  41. #include <fsutil.h>
  42. #include <fscache.h>
  43. #include <fsdm.h>
  44. #include <user/time.h>
  45.  
  46. /*
  47.  * Index operation type for AccessBlock routine.
  48.  */
  49. enum IndexOp { GET_ADDR, SET_ADDR, GROW_ADDR};
  50.  
  51. static ReturnStatus GrowBlock _ARGS_((Lfs *lfsPtr, 
  52.         Fsio_FileIOHandle *handlePtr, int blockNum, int blockSize,
  53.         LfsDiskAddr diskAddress, int cacheFlags));
  54.  
  55. static ReturnStatus AccessBlock _ARGS_((enum IndexOp op, Lfs *lfsPtr, 
  56.         Fsio_FileIOHandle *handlePtr, int blockNum, int blockSize,
  57.         int cacheFlags, LfsDiskAddr *diskAddressPtr));
  58. static ReturnStatus DeleteIndirectBlock _ARGS_((Lfs *lfsPtr, 
  59.         Fsio_FileIOHandle *handlePtr, int virtualBlockNum,
  60.         LfsDiskAddr *diskAddrPtr,
  61.         int startBlockNum, int lastBlockNum, int step, 
  62.         int lastByteBlock));
  63.  
  64.  
  65. /*
  66.  *----------------------------------------------------------------------
  67.  *
  68.  * LfsFile_GetIndex --
  69.  *
  70.  *    Return the disk address of the specified block of a specified file.
  71.  *
  72.  * Results:
  73.  *    A status indicating whether there was sufficient space to allocate
  74.  *    indirect blocks.
  75.  *
  76.  * Side effects:
  77.  *
  78.  *----------------------------------------------------------------------
  79.  */
  80.  
  81. ReturnStatus
  82. LfsFile_GetIndex(handlePtr, blockNum, cacheFlags, diskAddressPtr)
  83.     Fsio_FileIOHandle    *handlePtr;   /* Handle for file that are 
  84.                           * interest in. */
  85.     int                blockNum;    /* Block number of interest. */
  86.     int        cacheFlags;         /* FSCACHE_CANT_BLOCK,FSCACHE_DONT_BLOCK.*/
  87.     LfsDiskAddr *diskAddressPtr;      /* Disk address returned. */
  88. {
  89.     Lfs                *lfsPtr;
  90.     Fsdm_Domain            *domainPtr;
  91.     ReturnStatus        status;
  92.  
  93.     domainPtr = Fsdm_DomainFetch(handlePtr->hdr.fileID.major, TRUE);
  94.     if (domainPtr == (Fsdm_Domain *)NIL) {
  95.     return(FS_DOMAIN_UNAVAILABLE);
  96.     }
  97.     lfsPtr = LfsFromDomainPtr(domainPtr);
  98.     LFS_STATS_INC(lfsPtr->stats.index.get);
  99.     status = AccessBlock(GET_ADDR, lfsPtr, handlePtr, blockNum, 0, cacheFlags,
  100.                 diskAddressPtr);
  101.     Fsdm_DomainRelease(handlePtr->hdr.fileID.major);
  102.     return status;
  103. }
  104.  
  105. /*
  106.  *----------------------------------------------------------------------
  107.  *
  108.  * LfsFile_SetIndex --
  109.  *
  110.  *    Set the disk address of the specified block of a specified file.
  111.  *
  112.  * Results:
  113.  *    SUCCESS if operation worked. FS_WOULD_BLOCK if operation would
  114.  *    block and cantBlock argument set.
  115.  *
  116.  * Side effects:
  117.  *
  118.  *----------------------------------------------------------------------
  119.  */
  120.  
  121. ReturnStatus
  122. LfsFile_SetIndex(handlePtr, blockNum, blockSize, cacheFlags, diskAddress)
  123.     Fsio_FileIOHandle          *handlePtr;    /* Handle for file that are 
  124.                           * interest in. */
  125.     int            blockNum;          /* Block number of interest. */
  126.     int            blockSize;         /* Size of block in bytes. */
  127.     int        cacheFlags;         /* FSCACHE_CANT_BLOCK,FSCACHE_DONT_BLOCK.*/
  128.     LfsDiskAddr     diskAddress;              /* Disk address of block. */
  129. {
  130.     Lfs                *lfsPtr;
  131.     Fsdm_Domain            *domainPtr;
  132.     ReturnStatus        status;
  133.  
  134.     domainPtr = Fsdm_DomainFetch(handlePtr->hdr.fileID.major, TRUE);
  135.     if (domainPtr == (Fsdm_Domain *)NIL) {
  136.     return(FS_DOMAIN_UNAVAILABLE);
  137.     }
  138.     lfsPtr = LfsFromDomainPtr(domainPtr);
  139.     LFS_STATS_INC(lfsPtr->stats.index.set);
  140.     /*
  141.      * Checking. 
  142.      */
  143. #ifdef ERROR_CHECK
  144.    if (!LfsIsNilDiskAddr(diskAddress)) { 
  145.         int segNo;
  146.     segNo = LfsDiskAddrToSegmentNum(lfsPtr, diskAddress);
  147.     if (!LfsValidSegmentNum(lfsPtr,segNo)) {
  148.         panic("LfsFile_SetIndex: bad segment number.\n");
  149.     }
  150.     }
  151. #endif
  152.     status = AccessBlock(SET_ADDR, lfsPtr, handlePtr, blockNum, blockSize,
  153.         cacheFlags, &diskAddress);
  154.     Fsdm_DomainRelease(handlePtr->hdr.fileID.major);
  155.     return status;
  156. }
  157.  
  158. /*
  159.  *----------------------------------------------------------------------
  160.  *
  161.  * GrowBlock --
  162.  *
  163.  *    Grow the specified block to take occupy more space.
  164.  *
  165.  * Results:
  166.  *    SUCCESS if operation worked ok.
  167.  *    FS_WOULD_BLOCK if operation would block an cantBlock set.
  168.  *
  169.  * Side effects:
  170.  *    The block may be fetched into the cache and marked as
  171.  *    modified to get to be written to the log again.
  172.  *
  173.  *----------------------------------------------------------------------
  174.  */
  175. static ReturnStatus
  176. GrowBlock(lfsPtr, handlePtr, blockNum, growthSize, diskAddr, cacheFlags)
  177.     Lfs        *lfsPtr;             /* File system of file. */
  178.     Fsio_FileIOHandle          *handlePtr;    /* Handle for file that are 
  179.                           * interest in. */
  180.     int        blockNum;             /* Block number of file. */
  181.     int        growthSize;        /* Block growth size. */
  182.     LfsDiskAddr diskAddr;            /* Disk address of block. */
  183.     int        cacheFlags;         /* FSCACHE_CANT_BLOCK,FSCACHE_DONT_BLOCK.*/
  184. {
  185.     Fsdm_FileDescriptor *descPtr;
  186.     int origBlockSize;
  187.     Fscache_Block *blockPtr;
  188.     Boolean    found;
  189.     ReturnStatus    status = SUCCESS;
  190.  
  191.     if (LfsIsNilDiskAddr(diskAddr)) {
  192.     /*
  193.      * The block is not allocated on disk. Do nothing.
  194.      */
  195.     return SUCCESS;
  196.     }
  197.     descPtr = handlePtr->descPtr;
  198.  
  199.     origBlockSize = (descPtr->lastByte + 1) - blockNum * FS_BLOCK_SIZE;
  200.     if (origBlockSize <= 0) {
  201.     LfsError(lfsPtr, FAILURE, "GrowBlock: Bad original size of block\n");
  202.     return FAILURE;
  203.     }
  204.     origBlockSize = LfsBlocksToBytes(lfsPtr, 
  205.                 LfsBytesToBlocks(lfsPtr,origBlockSize));
  206.  
  207.     if (origBlockSize + growthSize > FS_BLOCK_SIZE) {
  208.     LfsError(lfsPtr, FAILURE, "GrowBlock: Bad  size of block\n");
  209.     return FAILURE;
  210.     }
  211.  
  212.     if (descPtr->fileType != FS_DIRECTORY) { 
  213.     /*
  214.      * If the file is not a directory we need to read the block in 
  215.      * and mark it as dirty so it will be written back. This
  216.      * is because the block now too small on disk and we must
  217.      * write it out with its new larger size. The reason why
  218.      * we must fetch the block is that the growth may be due
  219.      * to a write pass the end block of the file.  This causes the
  220.      * old last block to no longer be a fragment. The new bytes in
  221.      * this block must be zeros.  This can not happen for directories
  222.      * because the file system controls writes to directory blocks.
  223.      */
  224.     Fscache_FetchBlock(&handlePtr->cacheInfo, blockNum,
  225.             cacheFlags|FSCACHE_DATA_BLOCK, &blockPtr, &found);
  226.     if (!found) {
  227.         if (blockPtr == (Fscache_Block *) NIL) {
  228.         status = FS_WOULD_BLOCK;
  229.         return status;
  230.         }
  231.          status = LfsReadBytes(lfsPtr, diskAddr, origBlockSize, 
  232.                blockPtr->blockAddr);
  233.         bzero(blockPtr->blockAddr+origBlockSize, FS_BLOCK_SIZE-origBlockSize);
  234. #ifdef ERROR_CHECK
  235.          LfsCheckRead(lfsPtr, diskAddr, origBlockSize);
  236. #endif
  237.          if (status != SUCCESS) {
  238.          LfsError(lfsPtr, status, "Can't read block to grow.\n");
  239.          return status;
  240.          }
  241.     }
  242.  
  243.     Fscache_UnlockBlock(blockPtr,(time_t)Fsutil_TimeInSeconds(), 
  244.                 blockNum, origBlockSize+growthSize, 0);
  245.     }
  246.     /*
  247.      * Grow the active bytes of the segment. The activeBytes will
  248.      * be decremented when the file is deleted or the block is written
  249.      * out to disk.
  250.      */
  251.     LfsSetSegUsage(lfsPtr, LfsDiskAddrToSegmentNum(lfsPtr, diskAddr),
  252.             growthSize);
  253.     return status;
  254. }
  255.  
  256. /*
  257.  *----------------------------------------------------------------------
  258.  *
  259.  * AccessBlock --
  260.  *
  261.  *    Access and perform a GET or SET operation on the specified block
  262.  *    of the specified file.
  263.  *
  264.  * Results:
  265.  *    SUCCESS if operation worked ok.
  266.  *    FS_WOULD_BLOCK if operation would block an cantBlock set.
  267.  *
  268.  * Side effects:
  269.  *    Index block may be allocated.
  270.  *
  271.  *----------------------------------------------------------------------
  272.  */
  273.  
  274. static ReturnStatus
  275. AccessBlock(op, lfsPtr, handlePtr, blockNum, blockSize, cacheFlags, 
  276.         diskAddressPtr)
  277.     enum IndexOp           op;         /* Operation to be performed. 
  278.                           * Must be GET_ADDR,  
  279.                           * SET_ADDR or GROW_ADDR. */
  280.     Fsio_FileIOHandle          *handlePtr;    /* Handle for file that are 
  281.                           * interest in. */
  282.     Lfs        *lfsPtr;             /* File system of file. */
  283.     int        blockNum;             /* Block number of file. */
  284.     int        blockSize;        /* Block size for set operation */
  285.     int        cacheFlags;         /* FSCACHE_CANT_BLOCK,FSCACHE_DONT_BLOCK.*/
  286.     LfsDiskAddr *diskAddressPtr;        /* Disk address in/out. */
  287. {
  288.     int parentIndex, parentBlockNum;
  289.     LfsDiskAddr parentDiskAddress;
  290.     Fsdm_FileDescriptor     *descPtr;
  291.     Fscache_Block *parentblockPtr;
  292.     time_t    modTime;
  293.     Boolean    found;
  294.     ReturnStatus    status;
  295.     LfsDiskAddr *indirectPtr, *directPtr;
  296.  
  297.     descPtr = handlePtr->descPtr;
  298.     directPtr = (LfsDiskAddr *)(descPtr->direct);
  299.     indirectPtr = (LfsDiskAddr *)(descPtr->indirect);
  300.  
  301.     /*
  302.      * First process the data and indirect blocks that are pointed to 
  303.      * by the descriptor.
  304.      */
  305.     if (blockNum < 0) {
  306.     if (op == GROW_ADDR) {
  307.         panic("LfsAccessBlock - Can't grow indirect block\n");
  308.         return FAILURE;
  309.     }
  310.     if (blockNum >= -FSDM_NUM_INDIRECT_BLOCKS) { 
  311.         /*
  312.          * This is a direct indirect block.
  313.          */
  314.         if (op == GET_ADDR) { 
  315.         *diskAddressPtr = indirectPtr[(-blockNum)-1];
  316.         } else { /* SET_ADDR */
  317.         LfsDiskAddr *addrPtr = indirectPtr + ((-blockNum)-1);
  318.         LfsSegUsageFreeBlocks(lfsPtr, blockSize, 1, addrPtr);
  319.         *addrPtr = *diskAddressPtr;
  320.         descPtr->flags |= FSDM_FD_INDEX_DIRTY;
  321.         (void) Fsdm_FileDescStore(handlePtr, FALSE);
  322.         }
  323.         return(SUCCESS);
  324.      }
  325.      if (blockNum > -(FSDM_NUM_INDIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK)) {
  326.          parentIndex = (-blockNum) - (FSDM_NUM_INDIRECT_BLOCKS+1);
  327.          parentBlockNum = -2;
  328.      } else {
  329.         /*
  330.          * Past the largest file size that we support.
  331.          */
  332.         return(FS_INVALID_ARG);
  333.      }
  334.     } else { 
  335.     if (blockNum < FSDM_NUM_DIRECT_BLOCKS) {
  336.         /*
  337.          * This is a direct data block.
  338.          */
  339.         status = SUCCESS;
  340.         switch (op) {
  341.         case GET_ADDR: { 
  342.             *diskAddressPtr = directPtr[blockNum];
  343.             break;
  344.         }
  345.         case SET_ADDR: {
  346.             LfsDiskAddr *addrPtr = (directPtr + blockNum);
  347.             LfsSegUsageFreeBlocks(lfsPtr, blockSize, 1, addrPtr);
  348.             *addrPtr = *diskAddressPtr;
  349.             descPtr->flags |= FSDM_FD_INDEX_DIRTY;
  350.             (void) Fsdm_FileDescStore(handlePtr, FALSE);
  351.             break;
  352.         }
  353.         case GROW_ADDR: {
  354.             status = GrowBlock(lfsPtr, handlePtr, blockNum, 
  355.                 blockSize, directPtr[blockNum], 
  356.                 cacheFlags & 
  357.                    (FSCACHE_CANT_BLOCK|FSCACHE_DONT_BLOCK));
  358.             *diskAddressPtr = directPtr[blockNum];
  359.             break;
  360.         }
  361.         }
  362.         return(status);
  363.     }
  364.     if (blockNum < (FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK)) {
  365.         parentBlockNum = -1;
  366.         parentIndex = blockNum - FSDM_NUM_DIRECT_BLOCKS;
  367.     } else if (blockNum < FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK +
  368.                 FSDM_INDICES_PER_BLOCK*FSDM_INDICES_PER_BLOCK) {
  369.         parentBlockNum = -((FSDM_NUM_INDIRECT_BLOCKS+1) +
  370.           (blockNum - FSDM_NUM_DIRECT_BLOCKS - FSDM_INDICES_PER_BLOCK)/
  371.             FSDM_INDICES_PER_BLOCK);
  372.         parentIndex = (blockNum - FSDM_NUM_DIRECT_BLOCKS - 
  373.                FSDM_INDICES_PER_BLOCK) % FSDM_INDICES_PER_BLOCK;
  374.     } else {
  375.         /*
  376.          * Past the largest file size that we support.
  377.          */
  378.         return(FS_INVALID_ARG);
  379.     }
  380.  
  381.     }
  382.     cacheFlags |= ((op == SET_ADDR) ? 
  383.                   (FSCACHE_IND_BLOCK|FSCACHE_IO_IN_PROGRESS) 
  384.                     : FSCACHE_IND_BLOCK);
  385.  
  386.  
  387.     switch (op) {
  388.     case GET_ADDR: {
  389.         LFS_STATS_INC(lfsPtr->stats.index.getFetchBlock);
  390.         if (cacheFlags & FSCACHE_CANT_BLOCK) {
  391.         LFS_STATS_INC(lfsPtr->stats.index.getCleaningFetchBlock);
  392.         }
  393.         break;
  394.     }
  395.     case SET_ADDR: {
  396.         LFS_STATS_INC(lfsPtr->stats.index.setFetchBlock);
  397.         break;
  398.     } 
  399.     case GROW_ADDR: {
  400.         LFS_STATS_INC(lfsPtr->stats.index.growFetchBlock);
  401.         break;
  402.     } 
  403.     }
  404.      /* 
  405.      * Lookup the parent block in the cache.
  406.      */
  407.    Fscache_FetchBlock(&handlePtr->cacheInfo, parentBlockNum,
  408.         cacheFlags, &parentblockPtr, &found);
  409.     if ((parentblockPtr != (Fscache_Block *) NIL) && found) {
  410.     modTime = 0;
  411.      status = SUCCESS;
  412.      switch (op) {
  413.          case GET_ADDR: {
  414.         LFS_STATS_INC(lfsPtr->stats.index.getFetchHit);
  415.         if (cacheFlags & FSCACHE_CANT_BLOCK) {
  416.             LFS_STATS_INC(lfsPtr->stats.index.getCleaningFetchHit);
  417.         }
  418.         *diskAddressPtr = 
  419.             ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex];
  420.         break;
  421.          } 
  422.          case SET_ADDR: {
  423.         LfsDiskAddr *addrPtr;
  424.         addrPtr = ((LfsDiskAddr *)parentblockPtr->blockAddr) + 
  425.                parentIndex; 
  426.         LFS_STATS_INC(lfsPtr->stats.index.setFetchHit);
  427.         LfsSegUsageFreeBlocks(lfsPtr, blockSize, 1, addrPtr);
  428.         *addrPtr = *diskAddressPtr;
  429.         modTime = Fsutil_TimeInSeconds();
  430.         break;
  431.          }
  432.          case GROW_ADDR: {
  433.         *diskAddressPtr = 
  434.             ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex];
  435.         status = GrowBlock(lfsPtr, handlePtr, blockNum, 
  436.                 blockSize, *diskAddressPtr, 
  437.                 cacheFlags & 
  438.                    (FSCACHE_CANT_BLOCK|FSCACHE_DONT_BLOCK));
  439.         break;
  440.          } 
  441.      }
  442.      Fscache_UnlockBlock(parentblockPtr, modTime, parentBlockNum,
  443.                  FS_BLOCK_SIZE, 0);
  444.      return status;
  445.     }
  446.     if (parentblockPtr == (Fscache_Block *) NIL) {
  447.     return FS_WOULD_BLOCK;
  448.     }
  449.     /*
  450.      * Not found in cache. Try to read it in. First we need to find the
  451.      * address of the block.
  452.      */
  453.     status = AccessBlock(GET_ADDR, lfsPtr, handlePtr, parentBlockNum, 0,
  454.                 cacheFlags,
  455.                 &parentDiskAddress);
  456.     if (status != SUCCESS) {
  457.      Fscache_UnlockBlock(parentblockPtr, (time_t)0, parentBlockNum,
  458.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  459.     return status;
  460.     }
  461.     if (LfsIsNilDiskAddr(parentDiskAddress)) {
  462.     switch (op) {
  463.         case GROW_ADDR: 
  464.         case GET_ADDR: {
  465.          LfsSetNilDiskAddr(diskAddressPtr);
  466.          Fscache_UnlockBlock(parentblockPtr, (time_t)0,
  467.                  parentBlockNum,
  468.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  469.          break;
  470.         }
  471.         case SET_ADDR: {
  472.         register LfsDiskAddr *intPtr, *limitPtr;
  473.         limitPtr = (LfsDiskAddr *) (parentblockPtr->blockAddr + 
  474.                         FS_BLOCK_SIZE);
  475.         for (intPtr = (LfsDiskAddr *)parentblockPtr->blockAddr;
  476.                 intPtr < limitPtr; intPtr++) {
  477.             LfsSetNilDiskAddr(intPtr);
  478.         }
  479.         ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex] = 
  480.                 *diskAddressPtr;
  481.          Fscache_UnlockBlock(parentblockPtr,
  482.                      (time_t)Fsutil_TimeInSeconds(), 
  483.                      parentBlockNum, FS_BLOCK_SIZE, 0);
  484.          break;
  485.         }
  486.     }
  487.     return SUCCESS;
  488.      }
  489.  
  490.      status = LfsReadBytes(lfsPtr, parentDiskAddress, 
  491.         FS_BLOCK_SIZE,  parentblockPtr->blockAddr);
  492. #ifdef ERROR_CHECK
  493.      LfsCheckRead(lfsPtr, parentDiskAddress, FS_BLOCK_SIZE);
  494. #endif
  495.      if (status != SUCCESS) {
  496.      Fscache_UnlockBlock(parentblockPtr, (time_t)0, parentBlockNum,
  497.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  498.      LfsError(lfsPtr, status, "Can't read indirect block.\n");
  499.      return status;
  500.      }
  501.      modTime = 0;
  502.      switch (op) {
  503.      case GET_ADDR: {
  504.         *diskAddressPtr =  
  505.             ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex];
  506.         break;
  507.      }
  508.      case SET_ADDR: {
  509.         LfsDiskAddr *addrPtr = ((LfsDiskAddr *)parentblockPtr->blockAddr) + 
  510.                         parentIndex; 
  511.         LfsSegUsageFreeBlocks(lfsPtr, blockSize, 1, addrPtr);
  512.         *addrPtr = *diskAddressPtr;
  513.         modTime = Fsutil_TimeInSeconds();
  514.         break;
  515.      }
  516.      case GROW_ADDR: {
  517.         *diskAddressPtr =  
  518.             ((LfsDiskAddr *)parentblockPtr->blockAddr)[parentIndex];
  519.         status = GrowBlock(lfsPtr, handlePtr, blockNum, 
  520.                 blockSize, *diskAddressPtr, 
  521.                 cacheFlags & 
  522.                    (FSCACHE_CANT_BLOCK|FSCACHE_DONT_BLOCK));
  523.         break;
  524.      }
  525.     }
  526.     Fscache_UnlockBlock(parentblockPtr, modTime, parentBlockNum,
  527.             FS_BLOCK_SIZE, 0);
  528.     return(SUCCESS);
  529. }
  530.  
  531. /*
  532.  *----------------------------------------------------------------------
  533.  *
  534.  * DeleteIndirectBlock --
  535.  *
  536.  *    Deallocate and remove from the cache all blocks of the specified
  537.  *    file greater than the given block number.
  538.  *
  539.  * Results:
  540.  *    SUCCESS if all goes well or some error returned from DiskRead
  541.  *
  542.  * Side effects:
  543.  *    None.
  544.  *
  545.  *----------------------------------------------------------------------
  546.  */
  547.  
  548. static ReturnStatus
  549. DeleteIndirectBlock(lfsPtr, handlePtr, virtualBlockNum, diskAddrPtr, 
  550.     startBlockNum, lastBlockNum, step, lastByteBlock) 
  551.     Lfs      *lfsPtr;
  552.     Fsio_FileIOHandle          *handlePtr;    /* Handle for file that are 
  553.                           * interest in. */
  554.     int      virtualBlockNum;    /* Virtual block number for this indirect 
  555.                  * block. */
  556.     LfsDiskAddr      *diskAddrPtr;    /* Disk address of block. */
  557.     int      startBlockNum;    /* Starting block number of this virtual
  558.                  * Block. */
  559.     int      lastBlockNum;        /* New last block number of file. */
  560.     int      step;            /* Number of blocks covered by each virtual
  561.                  * block entry. */
  562.     int      lastByteBlock;    /* Block containing last byte of file. */
  563. {
  564.     Fscache_Block    *cacheBlockPtr;
  565.     LfsDiskAddr        diskAddr = *diskAddrPtr;
  566.     Boolean        found;
  567.     ReturnStatus    status = SUCCESS;
  568.     Boolean        blockInCache;
  569.     int            startElement, cstep, childBlockNum, i;
  570.     LfsDiskAddr    *blockArray;
  571.     /*
  572.      * If this index block hasn't been allocated yet and not in the  
  573.      * cache we still need to check to see if any of its children
  574.      * might be in the cache.  
  575.      */
  576.     LFS_STATS_INC(lfsPtr->stats.index.deleteFetchBlock);
  577.     blockInCache = TRUE;
  578.     Fscache_FetchBlock(&handlePtr->cacheInfo, virtualBlockNum,
  579.        (int)(FSCACHE_IO_IN_PROGRESS|FSCACHE_IND_BLOCK), &cacheBlockPtr,&found);
  580.     if (!found) {
  581.     if (LfsIsNilDiskAddr(diskAddr)) {
  582.         Fscache_UnlockBlock(cacheBlockPtr, (time_t)0, virtualBlockNum,
  583.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  584.         blockInCache = FALSE;
  585.     } else {
  586.         /*
  587.          * Read it into the cache if it on disk somewhere.
  588.          */
  589.         LFS_STATS_INC(lfsPtr->stats.index.deleteFetchBlockMiss);
  590.         status = LfsReadBytes(lfsPtr, diskAddr, FS_BLOCK_SIZE, 
  591.                cacheBlockPtr->blockAddr);
  592. #ifdef ERROR_CHECK
  593.          LfsCheckRead(lfsPtr, diskAddr, FS_BLOCK_SIZE);
  594. #endif
  595.          if (status != SUCCESS) {
  596.          LfsError(lfsPtr, status, "Can't read indirect block.\n");
  597.          return status;
  598.          }
  599.     }
  600.     }
  601.     /*
  602.      * Compute the starting element of the block to start deleting at.
  603.      * If step equals one we must be pointing to data blocks.
  604.      */
  605.     startElement = (lastBlockNum - startBlockNum)/step;
  606.     if (startElement < 0) {
  607.     startElement = 0;
  608.     } else if (startElement > FSDM_INDICES_PER_BLOCK) {
  609.     panic("Bad call to DeleteIndirectBlock\n");
  610.     }
  611.     if (step != 1) {
  612.     static LfsDiskAddr nilAddr;
  613.     LfsDiskAddr *addrPtr = &nilAddr;
  614.     cstep = step/FSDM_INDICES_PER_BLOCK;
  615.     startBlockNum = startBlockNum + startElement * step;
  616.     childBlockNum = -((FSDM_NUM_INDIRECT_BLOCKS+1)+startElement);
  617.     LfsSetNilDiskAddr(addrPtr);
  618.     for (i = startElement; i < FSDM_INDICES_PER_BLOCK; i++) { 
  619.         if (blockInCache) { 
  620.         addrPtr = ((LfsDiskAddr *) cacheBlockPtr->blockAddr) + i;
  621.         } 
  622.         status = DeleteIndirectBlock(lfsPtr, handlePtr, childBlockNum, 
  623.                 addrPtr, startBlockNum, lastBlockNum, cstep, 
  624.                 lastByteBlock);
  625.         startBlockNum += step;
  626.         childBlockNum--;
  627.     }
  628.     } else if (blockInCache) {
  629.     blockArray =  ((LfsDiskAddr *) cacheBlockPtr->blockAddr) + startElement;
  630.     /*
  631.      * Free the last block in the file handling the case that it
  632.      * is a fragment.
  633.      */
  634.     if ((lastByteBlock >= startBlockNum) && 
  635.         (lastByteBlock < startBlockNum + FSDM_INDICES_PER_BLOCK) &&
  636.         (lastByteBlock >= lastBlockNum)) {
  637.         int fragSize;
  638.         fragSize = handlePtr->descPtr->lastByte - 
  639.                 (lastByteBlock * FS_BLOCK_SIZE) + 1;
  640.         fragSize = LfsBlocksToBytes(lfsPtr, LfsBytesToBlocks(lfsPtr, 
  641.                             fragSize));
  642.  
  643.         (void) LfsSegUsageFreeBlocks(lfsPtr, fragSize, 1,
  644.             blockArray + (lastByteBlock - startBlockNum));
  645.     }
  646.     (void) LfsSegUsageFreeBlocks(lfsPtr, FS_BLOCK_SIZE, 
  647.             FSDM_INDICES_PER_BLOCK - startElement, blockArray);
  648.     }
  649.     if (blockInCache) { 
  650.     /*
  651.      * If we deleted all the indexes in this block we can delete the block.
  652.      */
  653.     if (startElement == 0) {
  654.         Fscache_UnlockBlock(cacheBlockPtr, (time_t)0, virtualBlockNum,
  655.                  FS_BLOCK_SIZE, FSCACHE_DELETE_BLOCK);
  656.         (void) LfsSegUsageFreeBlocks(lfsPtr, FS_BLOCK_SIZE, 1, diskAddrPtr);
  657.     } else {
  658.         Fscache_UnlockBlock(cacheBlockPtr,(time_t)Fsutil_TimeInSeconds(), 
  659.                 virtualBlockNum, FS_BLOCK_SIZE, 0);
  660.     }
  661.     }
  662.     return status;
  663. }
  664.  
  665. /*
  666.  *----------------------------------------------------------------------
  667.  *
  668.  * LfsFile_TruncIndex --
  669.  *
  670.  *    Truncate the index of the specified file to only be the specified
  671.  *    number of blocks in length.
  672.  *
  673.  * Results:
  674.  *    SUCCESS if all goes well, a return status otherwise.
  675.  *
  676.  * Side effects:
  677.  *    None.
  678.  *
  679.  *----------------------------------------------------------------------
  680.  */
  681. ReturnStatus 
  682. LfsFile_TruncIndex(lfsPtr, handlePtr, length)
  683.     Lfs                *lfsPtr;
  684.     Fsio_FileIOHandle    *handlePtr;    /* Handle for file that are 
  685.                      * interest in. */
  686.     int             length;      /* Number of bytes to 
  687.                       * leave in file. */
  688. {
  689.     Fsdm_FileDescriptor    *descPtr;
  690.     ReturnStatus    status = SUCCESS;
  691.     int            lastByteBlock, fragSize;
  692.     int            numBlocks;
  693.  
  694.     LFS_STATS_INC(lfsPtr->stats.index.truncs);
  695.     numBlocks = (length + (FS_BLOCK_SIZE-1))/FS_BLOCK_SIZE;
  696.     descPtr = handlePtr->descPtr;
  697.     lastByteBlock = descPtr->lastByte/FS_BLOCK_SIZE;
  698.  
  699.  
  700.     /*
  701.      * Delete any DBL_INDIRECT blocks left over from this truncate. This is
  702.      * necessary only if the old length had double indirect blocks.
  703.      */
  704.     if ((numBlocks < (FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK +
  705.              FSDM_INDICES_PER_BLOCK * FSDM_INDICES_PER_BLOCK)) &&
  706.     (lastByteBlock >= (FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK))) {
  707.     status = DeleteIndirectBlock(lfsPtr, handlePtr, -2, 
  708.             &(descPtr->indirect[1]),
  709.             FSDM_NUM_DIRECT_BLOCKS + FSDM_INDICES_PER_BLOCK,
  710.             numBlocks, FSDM_INDICES_PER_BLOCK, lastByteBlock);
  711.     }
  712.     /*
  713.      * Followed by any INDIRECT blocks if the old length had
  714.      * indirect blocks.
  715.      */
  716.     if ((numBlocks < (FSDM_INDICES_PER_BLOCK + FSDM_NUM_DIRECT_BLOCKS)) &&
  717.         (lastByteBlock >= FSDM_NUM_DIRECT_BLOCKS)) {
  718.     status = DeleteIndirectBlock(lfsPtr, handlePtr, -1, 
  719.             &(descPtr->indirect[0]),
  720.             FSDM_NUM_DIRECT_BLOCKS, numBlocks, 1, lastByteBlock);
  721.     }
  722.     /*
  723.      * Finally the DIRECT blocks.
  724.      */
  725.     if (numBlocks < FSDM_NUM_DIRECT_BLOCKS) {
  726.     /*
  727.      * The last block in the file may be a fragement. Free it first.
  728.      */
  729.     if ((descPtr->lastByte >= 0) &&
  730.         (lastByteBlock < FSDM_NUM_DIRECT_BLOCKS) && 
  731.         (lastByteBlock >= numBlocks)) {
  732.         /*
  733.          * Compute the size of the fragment and round it into lfs
  734.          * blocks.
  735.          */
  736.         fragSize = descPtr->lastByte - (lastByteBlock * FS_BLOCK_SIZE) + 1;
  737.         /*
  738.          * Round to the number of LFS blocks it would take.
  739.          */
  740.         fragSize = LfsBlocksToBytes(lfsPtr, 
  741.                 LfsBytesToBlocks(lfsPtr, fragSize));
  742.         (void) LfsSegUsageFreeBlocks(lfsPtr, fragSize, 1, 
  743.             ((LfsDiskAddr *)descPtr->direct) + lastByteBlock);
  744.     }
  745.     (void) LfsSegUsageFreeBlocks(lfsPtr, FS_BLOCK_SIZE, 
  746.             FSDM_NUM_DIRECT_BLOCKS - numBlocks,    
  747.             ((LfsDiskAddr *)descPtr->direct) + numBlocks);
  748.     }
  749.  
  750.     return status;
  751. }
  752.  
  753.  
  754. /*
  755.  *----------------------------------------------------------------------
  756.  *
  757.  * LfsFile_GrowBlock --
  758.  *
  759.  *    Grow the specified block of the specified file.
  760.  *
  761.  * Results:
  762.  *    A status indicating whether there was sufficient space to allocate
  763.  *    block
  764.  *
  765.  * Side effects:
  766.  *
  767.  *----------------------------------------------------------------------
  768.  */
  769.  
  770. ReturnStatus
  771. LfsFile_GrowBlock(lfsPtr, handlePtr, offset, numBytes)
  772.     Lfs                *lfsPtr;
  773.     Fsio_FileIOHandle    *handlePtr;   /* Handle for file that are 
  774.                        * interest in. */
  775.     int        offset;             /* Offset to allocate at. */
  776.     int        numBytes;         /* Number of bytes to make block. */
  777. {
  778.     ReturnStatus        status;
  779.     int    newLastByte,  blockNum;
  780.     register    Fsdm_FileDescriptor *descPtr;
  781.     LfsDiskAddr diskAddress;
  782.     int     oldSize, oldLastBlock;
  783.     char errMsg[1024];
  784.  
  785.     /*
  786.      * Process the common case that we are appending to the end of the file
  787.      * starting at a block boundry.  We know the block can't already exist
  788.      * so we don't need to grow it. 
  789.      */
  790.     descPtr = handlePtr->descPtr;
  791.     oldSize = descPtr->lastByte + 1;
  792.     LFS_STATS_INC(lfsPtr->stats.blockio.fastAllocs);
  793.     if ((offset % FS_BLOCK_SIZE == 0) && (offset == oldSize)) {
  794.     return LfsSegUsageAllocateBytes(lfsPtr, numBytes);
  795.     }
  796.     newLastByte = offset + numBytes - 1;
  797.     blockNum = offset / FS_BLOCK_SIZE;
  798.     oldLastBlock = oldSize / FS_BLOCK_SIZE;
  799.     if (newLastByte > descPtr->lastByte) {
  800.     int blocksToGrow, bytesToGrow, lastFragSize, extraBytes;
  801.     /*
  802.      * We are writing passed the end of the file. If the last block is 
  803.      * a fragment we must grow it.
  804.      */
  805.     lastFragSize = oldSize % FS_BLOCK_SIZE;
  806.     if (lastFragSize > 0) { 
  807.         int newLastFragSize;
  808.         newLastFragSize = lastFragSize + (newLastByte - descPtr->lastByte);
  809.         if (newLastFragSize > FS_BLOCK_SIZE) {
  810.         newLastFragSize = FS_BLOCK_SIZE;
  811.         }
  812.         blocksToGrow = LfsBytesToBlocks(lfsPtr, newLastFragSize) - 
  813.                 LfsBytesToBlocks(lfsPtr, lastFragSize);
  814.     } else {
  815.         /*
  816.          * The last block in the file was not a fragment. No need to
  817.          * grow it.
  818.          */
  819.         blocksToGrow = 0;
  820.     }
  821.     if (blocksToGrow > 0) {
  822.         bytesToGrow = LfsBlocksToBytes(lfsPtr,blocksToGrow);
  823.         /*
  824.          * Allocate and grow the last block of the file. At the same
  825.          * time we can allocate space if a new last block is being 
  826.          * created.
  827.          */
  828.         extraBytes = (oldLastBlock == blockNum) ? 0 : numBytes;
  829.         status = LfsSegUsageAllocateBytes(lfsPtr, bytesToGrow + extraBytes);
  830.         if (status == SUCCESS) {
  831.          /* If this block is already allocated to disk and we are 
  832.           * growing it, increment the segment usage count to reflect 
  833.           * the larger block size so it will be correctly freed 
  834.           * when it is overwritten or deleted. 
  835.           */
  836.         LFS_STATS_INC(lfsPtr->stats.blockio.slowAllocs);
  837.         status = AccessBlock(GROW_ADDR, lfsPtr, handlePtr, 
  838.                   oldLastBlock, bytesToGrow, 0, &diskAddress);
  839.         } 
  840.     } else if (oldLastBlock != blockNum) {
  841.         /*
  842.          * The last block of the file doesn't need to be grown any but
  843.          * the write is creating a new last block that we must allocate
  844.          * space for.
  845.          */
  846.         status = LfsSegUsageAllocateBytes(lfsPtr, numBytes);
  847.     } else {
  848.         /*
  849.          * The write is to the last block of the file but doesn't cause
  850.          * the file to take any more space on disk because space is 
  851.          * rounded to block sizes.
  852.          */
  853.         status = SUCCESS;
  854.     }
  855.     } else {
  856.     /*
  857.      * We are writing into the middle of the file. Check to see if 
  858.      * the block previous existed. We can skip this check if we
  859.      * know that the file system has enough room for this block.
  860.      */
  861.     LFS_STATS_INC(lfsPtr->stats.blockio.fastAllocs);
  862.     status = LfsSegUsageAllocateBytes(lfsPtr, numBytes);
  863.     if (status != SUCCESS) { 
  864.         LFS_STATS_INC(lfsPtr->stats.blockio.slowAllocs);
  865.         status = AccessBlock(GET_ADDR, lfsPtr, handlePtr, blockNum, 
  866.                 FS_BLOCK_SIZE, 0, &diskAddress);
  867.         if ((status != SUCCESS) || LfsIsNilDiskAddr(diskAddress)) {
  868.         LFS_STATS_INC(lfsPtr->stats.blockio.slowAllocFails);
  869.         sprintf(errMsg, "LfsFile_GrowBlock: no space on %s.\n",
  870.             lfsPtr->name); /* DEBUG */
  871.         if (Timer_OkToWhine(errMsg)) {
  872.             printf(errMsg);
  873.         }
  874.         status = FS_NO_DISK_SPACE;
  875.         }
  876.     }
  877.  
  878.     }
  879.  
  880.     return status;
  881. }
  882.  
  883.